package com.ainiyar.springweb.controller.admin;

import com.ainiyar.springweb.common.constant.SYSConstant;
import com.ainiyar.springweb.common.result.ResultResponse;
import com.ainiyar.springweb.mapper.ImgFilesMapper;
import com.ainiyar.springweb.mapper.ImgGroupMapper;
import com.ainiyar.springweb.pojo.admin.dto.ChangePasswordDto;
import com.ainiyar.springweb.pojo.admin.dto.PageDto;
import com.ainiyar.springweb.pojo.entity.Admin;
import com.ainiyar.springweb.pojo.admin.vo.LoginAdminInfoVo;
import com.ainiyar.springweb.pojo.entity.ImgFiles;
import com.ainiyar.springweb.pojo.entity.ImgGroup;
import com.ainiyar.springweb.service.AdminService;
import com.ainiyar.springweb.util.*;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.If;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.update.UpdateChain;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.ainiyar.springweb.pojo.entity.table.ImgFilesTableDef.IMG_FILES;

/**************************************
 * File Name : SYSController
 * Created with : IntelliJ IDEA.
 * Author : 艾尼亚尔·毛拉吾提
 * QQ : 524155792  WeChat : ainiyar0124
 * Created Time : 2024/2/4  16:14
 * Desc :系统设置控制器
 ***************************************/
@RestController
public class SYSController {
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private AdminService adminService;
    @Resource
    private JWTUtil jwtUtil;
    @Resource
    private ImgGroupMapper imgGroupMapper;
    @Resource
    private ImgFilesMapper imgFilesMapper;

    /**
     * 后台登录页面验证码
     *
     * @return 验证码
     */
    @GetMapping("/captcha")
    public ResultResponse<Object> getCaptcha() {
        Map<String, Object> captcha = CaptchaUtil.getCaptcha();
        //存放redis
        long expire_time = 300L; //验证码有效期为5分钟
        redisUtil.set((String) captcha.get("key"), captcha.get("value"), expire_time);
        Map<String, Object> captcha_img = new HashMap<String, Object>(2) {{
            put("img", captcha.get("img"));
            put("key", captcha.get("key"));
        }};
        return ResultResponse.Result(captcha_img);
    }

    /**
     * 退出当前登录账号
     *
     * @param request  请求体
     * @param response 返回体
     * @return String
     */
    @GetMapping("/sys/logout")
    public ResultResponse<String> logOut(HttpServletRequest request, HttpServletResponse response) {
        //请求头部获取token
        String token = TokenUtil.handelToken(request);
        //从springSecurity上下文中获取用户信息
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication != null) {
            new SecurityContextLogoutHandler().logout(request, response, authentication);
            //从redis中删除token
        }
        return ResultResponse.Success(SYSConstant.ACCOUNT_LOGOUT_SUCCESS);
    }

    /**
     * 获取当前登录账号信息
     *
     * @return 当前登录人信息
     */
    @GetMapping("/sys/get_info")
    public ResultResponse<LoginAdminInfoVo> getLoginAdminInfo() {
        //从springSecurity上下文中获取用户信息
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        //判断authentication是否为空
        if (authentication == null) {
            return ResultResponse.Fail(SYSConstant.FIND_ADMINS_FAIL);
        }
        //获取管理员信息
        Admin admin = (Admin) authentication.getPrincipal();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        String create_time = admin.getCreateTime().format(formatter);
        String role_name = null;
        if (admin.getIsSupper() == 1) {
            role_name = "超级管理员";
        }
        LoginAdminInfoVo loginAdminInfoVo = new LoginAdminInfoVo(admin.getNickName(), admin.getUsername(), admin.getAvatar(), admin.getEMail(), admin.getPhone(), role_name, create_time);
        return ResultResponse.Result(loginAdminInfoVo);
    }

    /**
     * 更新当前登录人信息
     *
     * @param adminData 参数
     * @return 操作提示
     */
    @PostMapping("/sys/update_login_data")
    public ResultResponse<String> updateLoginAdminData(Admin adminData) {
        //从springSecurity上下文中获取用户信息
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        //获取管理员信息
        Admin admin = (Admin) authentication.getPrincipal();
        Admin adminEntity = new Admin();
        adminEntity.setId(admin.getId());
        adminEntity.setNickName(adminData.getNickName());
        adminEntity.setEMail(adminData.getEMail());
        adminEntity.setPhone(adminData.getPhone());
        if (!adminService.saveAddEditAdmin(adminEntity)) {
            return ResultResponse.Fail(SYSConstant.EDIT_ADMIN_DATA_ERROR);
        }
        return ResultResponse.Success(SYSConstant.EDIT_ADMIN_DATA_SUCCESS);
    }

    /**
     * 修改密码
     *
     * @param passwordDto 修改密码所需参数
     * @return String
     */
    @PostMapping("/sys/change_password")
    public ResultResponse<String> changePassword(ChangePasswordDto passwordDto) {
        //从springSecurity上下文中获取用户信息
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        //判断authentication是否为空
        if (authentication == null) {
            return ResultResponse.Fail(SYSConstant.ACCOUNT_CHANGE_PASSWORD_ERROR);
        }
        //获取管理员信息
        Admin admin = (Admin) authentication.getPrincipal();
        PasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        if (!bCryptPasswordEncoder.matches(passwordDto.getOldPassword().trim(), admin.getPassword())) {
            return ResultResponse.Fail(SYSConstant.ACCOUNT_CHANGE_PASSWORD_I_OLD_PASS);
        }
        if (!passwordDto.getPassword().trim().equals(passwordDto.getConfirmPassword().trim())) {
            return ResultResponse.Fail(SYSConstant.ACCOUNT_CHANGE_PASSWORD_CONFIRM_PASS_DIFFERENT);
        }
        Admin adminEntity = new Admin();
        adminEntity.setId(admin.getId());
        adminEntity.setPassword(passwordDto.getConfirmPassword().trim());
        if (!adminService.saveAddEditAdmin(adminEntity)) {
            return ResultResponse.Fail(SYSConstant.ACCOUNT_CHANGE_PASSWORD_ERROR);
        }
        return ResultResponse.Success(SYSConstant.ACCOUNT_CHANGE_PASSWORD_SUCCESS);
    }

    /**
     * 上传头像
     *
     * @param file 上传图片文件
     * @return 返回上传的图片
     * @throws IOException 异常
     */
    @PostMapping("/sys/upload_avatar")
    public ResultResponse<Object> uploadAvatar(MultipartFile file) throws IOException {
        //从springSecurity上下文中获取用户信息
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        //判断authentication是否为空
        if (authentication == null) {
            return ResultResponse.Fail(SYSConstant.CHANGE_AVATAR_ERROR);
        }
        String flag = FileUtil.uploadFile(file, "avatar");
        Admin admin = (Admin) authentication.getPrincipal();
        Admin adminEntity = new Admin();
        adminEntity.setId(admin.getId());
        adminEntity.setAvatar(flag);
        Map<String, Object> map = new HashMap<>();
        if (!adminService.saveAddEditAdmin(adminEntity)) {
            return ResultResponse.Fail(SYSConstant.CHANGE_AVATAR_ERROR);
        }
        map.put("avatar", flag);
        return ResultResponse.Result(map, SYSConstant.CHANGE_AVATAR_SUCCESS);
    }

    /**
     * 上传文件
     *
     * @param file 文件
     * @param type 类型  如：avtar:头像 等等
     */
    @PostMapping("/sys/upload_file")
    public ResultResponse<Object> uploadFile(MultipartFile file, @RequestParam(value = "type", defaultValue = "file") String type) throws IOException {
        String flag = FileUtil.uploadFile(file, type);
        Map<String, Object> map = new HashMap<>();
        map.put("file", flag);
        return ResultResponse.Result(map, "上传成功");
    }

    /**
     * 上传图片
     *
     * @param file  图片
     * @param group 分组id
     * @throws IOException 异常
     */
    @PostMapping("/sys/upload_img")
    public ResultResponse<Object> uploadImg(MultipartFile file, @RequestParam(value = "group", defaultValue = "0") Integer group) throws IOException {
        Map<String, String> img = FileUtil.uploadImg(file);
        ImgFiles imgFiles = new ImgFiles();
        imgFiles.setName(img.get("name"));
        imgFiles.setSrc(img.get("src"));
        imgFiles.setGroupId(group < 0 ? 0 : group);
        if (imgFilesMapper.insertSelective(imgFiles) > 0) {
            return ResultResponse.Success("上传图片成功");
        }
        return ResultResponse.Fail("上传图片失败");
    }

    /**
     * 图片上传组件 图片列表
     *
     * @param pageDto 分页参数
     * @param group   分组id
     * @param name    图片名称
     */
    @GetMapping("/sys/img_list")
    public ResultResponse<Map<String, Object>> getImgList(PageDto pageDto, @RequestParam(value = "group") Integer group, @RequestParam(value = "name") String name) {
        Integer group_id = group < 0 ? null : group;
        QueryWrapper queryWrapper = QueryWrapper.create()
                .select(IMG_FILES.ID, IMG_FILES.NAME, IMG_FILES.GROUP_ID, IMG_FILES.SRC, IMG_FILES.THUMB)
                .where(IMG_FILES.NAME.like(name, If::hasText))
                .and(IMG_FILES.GROUP_ID.eq(group_id, If::notNull))
                .orderBy(IMG_FILES.ID.desc());
        Page<ImgFiles> imgPage = Page.of(pageDto.getPage(), pageDto.getPageSize());
        imgPage = imgFilesMapper.paginate(imgPage, queryWrapper);
        Map<String, Object> list = new HashMap<>();
        list.put("list", imgPage.getRecords());
        list.put("total", imgPage.getTotalRow());
        list.put("totalPage", imgPage.getTotalPage());
        return ResultResponse.Result(list);
    }

    /**
     * 删除图片
     *
     * @param src 图片src
     */
    @DeleteMapping("/sys/img_del/{src}")
    public ResultResponse<String> delImgFile(@PathVariable String src) {
        System.out.println("id:" + src);
        QueryWrapper queryWrapper = QueryWrapper.create()
                .where(IMG_FILES.SRC.eq(src));
        if (imgFilesMapper.deleteByQuery(queryWrapper) > 0 && FileUtil.del(src)) {
            return ResultResponse.Success("删除成功");
        }
        return ResultResponse.Fail("删除失败");
    }

    /**
     * 新建图片分组
     * @param name 分组名称
     * @return 新建分组数据
     */
    @PostMapping("/sys/add_img_group")
    public ResultResponse<Map<String,String>> addImgGroup(@RequestParam(value = "name") String name){
        ImgGroup group=new ImgGroup();
        group.setName(name);
        if (imgGroupMapper.insertSelective(group)>0){
            Map<String,String> map=new HashMap<>();
            map.put("key", String.valueOf(group.getId()));
            map.put("label",name);
            return ResultResponse.Result(map,"新建分组成功");
        }
        return ResultResponse.Fail("新建分组失败");
    }

    /**
     * 修改图片分组
     * @param id id
     * @param name 分组名称
     */
    @PutMapping ("/sys/edit_img_group")
    public ResultResponse<String> editImgGroup(@RequestParam(value = "id") Integer id,@RequestParam(value = "name") String name){
        ImgGroup group=new ImgGroup();
        group.setName(name);
        group.setId(id);

        if (imgGroupMapper.update(group)>0){
            return ResultResponse.Success("修改分组成功");
        }
        return ResultResponse.Fail("修改分组失败");
    }

    /**
     * 图片分组列表
     */
    @GetMapping("/sys/img_group_list")
    public ResultResponse<List<Map<String,String>>> groupList(){
        List<ImgGroup> list = imgGroupMapper.selectAll();
        List<Map<String,String>> result=new ArrayList<>();
        for (ImgGroup record:list){
            Map<String,String> map=new HashMap<>();
            map.put("label",record.getName());
            map.put("key", String.valueOf(record.getId()));
            result.add(map);
        }
        return ResultResponse.Result(result);
    }

    /**
     * 删除图片分组
     * @param id 分组id
     */
    @DeleteMapping("/sys/del_img_group/{id}")
    public ResultResponse<String> delImgGroup(@PathVariable Integer id){
        System.out.println("id:"+id);
        try{
            UpdateChain.of(ImgFiles.class)
                    .set(ImgFiles::getGroupId, 0)
                    .where(ImgFiles::getGroupId).eq(id)
                    .update();
            imgGroupMapper.deleteById(id);
        }catch (Exception e){
            e.printStackTrace();
            return ResultResponse.Fail("删除失败");
        }
        return ResultResponse.Success("删除成功");
    }
    /**
     * 在线预览图片等文件
     *
     * @param flag     文件名
     * @param response 返回结构体
     */
    @GetMapping("/file/{flag}")
    public void files(@PathVariable String flag, HttpServletResponse response) {
        FileUtil.download(flag, response);
    }

    /**
     * 无感刷新token
     *
     * @param request 请求体
     * @return 新token
     */
    @GetMapping("/sys/refresh_token")
    public ResultResponse<Object> refreshToken(HttpServletRequest request) {
        String token = TokenUtil.handelToken(request);
        //从springSecurity上下文中获取用户信息
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        Admin admin = (Admin) authentication.getPrincipal();
        String newToken = "";
        //生成新的token
        if (jwtUtil.isTokenValid(token, admin.getUsername())) {
            newToken = jwtUtil.refreshToken(token, admin.getUsername());
        }
        //获取新token过期时间
        Long expireTime = null;
        if (!newToken.isEmpty()) {
            expireTime = jwtUtil.extractTime(newToken);
        }
        Map<String, Object> tokens = new HashMap<>();
        tokens.put("token", newToken);
        tokens.put("expireTime", expireTime);
        if (tokens.get("token") == null) {
            return ResultResponse.Fail("token刷新失败");
        }
        return ResultResponse.Result(tokens, "token刷新成功");
    }

}

